/*
	Copyright (c) 2009-2011, Stefan Webb.

	This file is part of SimpleML. Please read the file "license.txt", 
	which contains the conditions under which this software is distributed.
*/

/*!
	\file unicode.h
	\author Stefan Webb
	\brief Definition of Unicode class and related definitions.
*/

#ifndef UNICODE_H
#define UNICODE_H

/*! \brief Type definition for UTF-32 character on Windows. */
typedef unsigned int utf32;

/*! \brief Type definition for UTF-16 character. */
#ifdef WINDOWS
typedef wchar_t utf16;
#else
typedef unsigned short utf16;
#endif

/*! \brief Type definition for UTF-8 character. */
typedef unsigned char utf8;

namespace Unicode
{

/*! \brief General categories and subcategories of Unicode characters. */
enum GeneralCategory {
	LU, // Letter, Uppercase
	LL, // Letter, Lowercase
	LT, // Letter, Titlecase
	LM, // Letter, Modifier
	LO, // Letter, Other
	MN, // Mark, Nonspacing
	MC, // Mark, Spacing Combining
	ME, // Mark, Enclosing
	ND, // Number, Decimal Digit
	NL, // Number, Letter
	NO, // Number, Other
	PC, // Punctuation, Connector
	PD, // Punctuation, Dash
	PS, // Punctuation, Open
	PE, // Punctuation, Close
	PI, // Punctuation, Initial quote (may behave like Ps or Pe depending on usage)
	PF, // Punctuation, Final quote (may behave like Ps or Pe depending on usage)
	PO, // Punctuation, Other
	SM, // Symbol, Math
	SC, // Symbol, Currency
	SK, // Symbol, Modifier
	SO, // Symbol, Other
	ZS, // Separator, Space
	ZL, // Separator, Line
	ZP, // Separator, Paragraph
	CC, // Other, Control
	CF, // Other, Format
	CS, // Other, Surrogate
	CO, // Other, Private Use
	CN, // Other, Not Assigned (no characters in the file have this property)
	LETTER,
	MARK,
	NUMBER,
	PUNCTUATION,
	SYMBOL,
	SEPARATOR,
	OTHER
};

// Functions for using Unicode.

/*!	\brief Compare two UTF-8 strings.
	\param first First string to compare.
	\param second Second string to compare.
	\return True if strings are equal, false otherwise. */
bool areEqual(utf8* first, utf8* second);

/*!	\brief Compare two UTF-16 strings.
	\param first First string to compare.
	\param second Second string to compare.
	\return True if strings are equal, false otherwise. */
bool areEqual(utf16* first, utf16* second);

/*! \brief Classifies a UTF-32 character into its general category.
	\param character A UTF-32 character to classify.
	\return Classification of character. */
GeneralCategory classifyCharacter(utf32 character);

/*! \brief Compare n characters of two UTF-8 strings.
	\param first First string to compare.
	\param second Second string to compare.
	\param length Number of characters to match.
	\return True if characters match, false otherwise. */
bool compareCharacters(utf8* first, utf8* second, unsigned int length);

/*! \brief Compare n characters of two UTF-16 strings.
	\param first First string to compare.
	\param second Second string to compare.
	\param length Number of characters to match.
	\return True if characters match, false otherwise. */
bool compareCharacters(utf16* first, utf16* second, unsigned int length);

/*! \brief Decodes a UTF-8 character into a UTF-32 character.
	\param characters Pointer to character to decode.
	\return Decoded character, or 0 if invalid code point. */
utf32 decodeCharacter(utf8*& characters);

/*! \brief Decodes a UTF-16 character into a UTF-32 character. Note that the caller
	must have checked that there are not hanging surrogates beforehand, or else
	invalid memory could be accessed.
	\param characters Pointer to character to decode.
	\return Decoded character, or 0 if invalid surrogate pair. */
utf32 decodeCharacter(utf16*& characters);

/*! \brief Decrement pointer to UTF-8 string.
	\param string String pointer to decrement. */
void decrementPointer(utf8*& string);

/*! \brief Decrement pointer to UTF-16 string.
	\param string String pointer to decrement. */
void decrementPointer(utf16*& string);

/*! \brief Increment pointer to UTF-8 string.
	\param string String pointer to increment. */
void incrementPointer(utf8*& string);

/*! \brief Increment pointer to UTF-16 string.
	\param string String pointer to increment. */
void incrementPointer(utf16*& string);

/*! \brief Detect if character is first half of a surrogate pair.
	\param character Character to test.
	\return True if character is first half of surrogate pair, false otherwise. */
bool isFirstSurrogate(utf16 character);

/*! \brief Determine if new line present and if so then update position.
	\param position Pointer to search position.
	\param final Pointer to end of string.
	\bool Returns new if new line was present. False, otherwise. */
bool isNewLine(utf8*& position, utf8* final);

/*! \brief Determine if new line present and if so then update position.
	\param position Pointer to search position.
	\param final Pointer to end of string.
	\bool Returns new if new line was present. False, otherwise. */
bool isNewLine(utf16*& position, utf16* final);

/*! \brief Detect if character is second half of a surrogate pair.
	\param character Character to test.
	\return True if character is second half of surrogate pair, false otherwise. */
bool isSecondSurrogate(utf16 character);

/*! \brief Check if character is valid UTF-8.
	\param position Pointer to search position.
	\param final Pointer to end of string. */
bool isValidCharacter(utf8* position, utf8* final);

/*! \brief Check if character is valid UTF-16, that is, check surrogate pairs.
	\param position Pointer to search position.
	\param final Pointer to end of string. */
bool isValidCharacter(utf16* position, utf16* final);

/*! \brief Determine if character is white space.
	\param character Character which to test for white space.
	\bool Returns true if character is white space. False, otherwise. */
bool isWhitespace(utf32 character);

/*! \brief Calculate length in code units (not code points) of UTF-8 string.
	\param string Zero-termianted UTF-8 string.
	\return Length of string in characters. */
unsigned int lengthString(utf8* string);

/*! \brief Calculate length in code units (not code points) of UTF-16 string.
	\param string Zero-termianted UTF-16 string.
	\return Length of string in characters. */
unsigned int lengthString(utf16* string);

/*! \brief Test if string contains valid scalar. Update pointer past scalar.
	\param string Pointer for which to test for valid scalar.
	\return True if string contains valid scalar. False, otherwise. */
bool isValidScalar(utf8*& string);

/*! \brief Test if string contains valid scalar. Update pointer past scalar.
	\param string Pointer for which to test for valid scalar.
	\return True if string contains valid scalar. False, otherwise. */
bool isValidScalar(utf16*& string);

/*! \brief Test if string contains valid unsigned integer. Update pointer past integer.
	\param string Pointer for which to test for valid unsigned integer.
	\return True if string contains valid unsigned integer. False otherwise. */
bool isValidInteger(utf8*& string);

/*! \brief Test if string contains valid unsigned integer. Update pointer past integer.
	\param string Pointer for which to test for valid unsigned integer.
	\return True if string contains valid unsigned integer. False otherwise. */
bool isValidInteger(utf16*& string);

/*! \brief Keep incrementing pointer until next scalar is reached.
	\param string Pointer to increment.
	\return True if string contains more characters. False, otherwise. */
bool nextScalar(utf8*& string);

/*! \brief Keep incrementing pointer until next scalar is reached.
	\param string Pointer to increment.
	\return True if string contains more characters. False, otherwise. */
bool nextScalar(utf16*& string);

/*!	\brief Increment pointer until skipped separator (comma and whitespace).
	\param string Pointer to increment.
	\return True if string contains more characters. False, otherwise. */
bool skipSeparator(utf8*& string);

/*!	\brief Increment pointer until skipped separator (comma and whitespace).
	\param string Pointer to increment.
	\return True if string contains more characters. False, otherwise. */
bool skipSeparator(utf16*& string);

/*! \brief Increment pointer until skipped scalar (assuming it is valid).
	\param string Pointer to increment.
	\return True if string contains more characters. False, otherwise. */
bool skipScalar(utf8*& string);

/*! \brief Increment pointer until skipped scalar (assuming it is valid).
	\param string Pointer to increment.
	\return True if string contains more characters. False, otherwise. */
bool skipScalar(utf16*& string);

/*! \brief Incrementing pointer until skipped whitespace.
	\param string Pointer for which to skip whitespace. */
void skipWhitespace(utf8*& string);

/*! \brief Incrementing pointer until skipped whitespace.
	\param string Pointer for which to skip whitespace. */
void skipWhitespace(utf16*& string);

/*! \brief Subclassfies (grouping similar categories together) a UTF-32 character.
	\param character A UTF-32 character to subclassify.
	\return Subclassification of character. */
GeneralCategory subclassifyCharacter(utf32 character);

/*! \brief Convert UTF-8 string to single precision floating number.
	\param input Pointer to input string.
	\param output Reference to converted float.
	\return True if conversion was successful. False, otherwise. */
bool toFloat(utf8* input, float& output);

/*! \brief Convert UTF-16 string to single precision floating number.
	\param input Pointer to input string.
	\param output Reference to converted float.
	\return True if conversion was successful. False, otherwise. */
bool toFloat(utf16* input, float& output);

/*! \brief Convert UTF-8 string to double precision floating number.
	\param input Pointer to input string.
	\param output Reference to converted float.
	\return True if conversion was successful. False, otherwise. */
bool toFloat(utf8* input, double& output);

/*! \brief Convert UTF-16 string to double precision floating number.
	\param input Pointer to input string.
	\param output Reference to converted float.
	\return True if conversion was successful. False, otherwise. */
bool toFloat(utf16* input, double& output);

/*! \brief Convert UTF-8 string to signed integer.
	\param input Pointer to input string.
	\param output Reference to converted integer.
	\return True if conversion was successful. False, otherwise. */
bool toInteger(utf8* input, int& output);

/*! \brief Convert UTF-16 string to signed integer.
	\param input Pointer to input string.
	\param output Reference to converted integer.
	\return True if conversion was successful. False, otherwise. */
bool toInteger(utf16* input, int& output);

/*! \brief Convert UTF-8 string to UTF-16 string. Ensure buffers are right size.
	\param input Pointer to input string.
	\param output Pointer to output string.
	\return True if conversion was successful. False, otherwise. */
bool toString(utf8* input, utf16* output);

/*! \brief Convert UTF-16 string to UTF-8 string. Ensure buffers are right size.
	\param input Pointer to input string.
	\param output Pointer to output string.
	\return True if conversion was successful. False, otherwise. */
bool toString(utf16* input, utf8* output);

/*! \brief Convert signed 8-bit integer to UTF-8 string.
	\param input Signed char to convert.
	\param output Pointer to output string.
	\return True if conversion was successful. False, otherwise. */
bool toString(char input, utf8* output);

/*! \brief Convert signed 8-bit integer to UTF-16 string.
	\param input Signed char to convert.
	\param output Pointer to output string.
	\return True if conversion was successful. False, otherwise. */
bool toString(char input, utf16* output);

/*! \brief Convert unsigned 8-bit integer to UTF-8 string.
	\param input Unsigned char to convert.
	\param output Pointer to output string.
	\return True if conversion was successful. False, otherwise. */
bool toString(unsigned char input, utf8* output);

/*! \brief Convert unsigned 8-bit integer to UTF-16 string.
	\param input Unsigned char to convert.
	\param output Pointer to output string.
	\return True if conversion was successful. False, otherwise. */
bool toString(unsigned char input, utf16* output);

/*! \brief Convert signed 16-bit integer to UTF-8 string.
	\param input Signed short to convert.
	\param output Pointer to output string.
	\return True if conversion was successful. False, otherwise. */
bool toString(short input, utf8* output);

/*! \brief Convert signed 16-bit integer to UTF-16 string.
	\param input Signed short to convert.
	\param output Pointer to output string.
	\return True if conversion was successful. False, otherwise. */
bool toString(short input, utf16* output);

/*! \brief Convert unsigned 16-bit integer UTF-8 string.
	\param input Unsigned short to convert.
	\param output Pointer to output string.
	\return True if conversion was successful. False, otherwise. */
bool toString(unsigned short input, utf8* output);

/*! \brief Convert unsigned 16-bit integer UTF-16 string.
	\param input Unsigned short to convert.
	\param output Pointer to output string.
	\return True if conversion was successful. False, otherwise. */
bool toString(unsigned short input, utf16* output);

/*! \brief Convert signed 32-bit integer to UTF-8 string.
	\param input Signed int to convert.
	\param output Pointer to output string.
	\return True if conversion was successful. False, otherwise. */
bool toString(int input, utf8* output);

/*! \brief Convert signed 32-bit integer to UTF-16 string.
	\param input Signed int to convert.
	\param output Pointer to output string.
	\return True if conversion was successful. False, otherwise. */
bool toString(int input, utf16* output);

/*! \brief Convert unsigned 32-bit integer to UTF-8 string.
	\param input Unsigned int to convert.
	\param output Pointer to output string.
	\return True if conversion was successful. False, otherwise. */
bool toString(unsigned int input, utf8* output);

/*! \brief Convert unsigned 32-bit integer to UTF-16 string.
	\param input Unsigned int to convert.
	\param output Pointer to output string.
	\return True if conversion was successful. False, otherwise. */
bool toString(unsigned int input, utf16* output);

/*! \brief Convert signed 64-bit integer to UTF-8 string.
	\param input Signed long long to convert.
	\param output Pointer to output string.
	\return True if conversion was successful. False, otherwise. */
bool toString(long long input, utf8* output);

/*! \brief Convert signed 64-bit integer to UTF-16 string.
	\param input Signed long long to convert.
	\param output Pointer to output string.
	\return True if conversion was successful. False, otherwise. */
bool toString(long long input, utf16* output);

/*! \brief Convert unsigned 64-bit integer to UTF-8 string.
	\param input Unsigned long long to convert.
	\param output Pointer to output string.
	\return True if conversion was successful. False, otherwise. */
bool toString(unsigned long long input, utf8* output);

/*! \brief Convert unsigned 64-bit integer to UTF-16 string.
	\param input Unsigned long long to convert.
	\param output Pointer to output string.
	\return True if conversion was successful. False, otherwise. */
bool toString(unsigned long long input, utf16* output);

/*! \brief Convert single precision floating number to UTF-8 string.
	\param input Float to convert.
	\param output Pointer to output string.
	\return True if conversion was successful. False, otherwise. */
bool toString(float input, utf8* output);

/*! \brief Convert single precision floating number to UTF-16 string.
	\param input Float to convert.
	\param output Pointer to output string.
	\return True if conversion was successful. False, otherwise. */
bool toString(float input, utf16* output);

/*! \brief Convert double precision floating number to UTF-8 string.
	\param input Double to convert.
	\param output Pointer to output string.
	\return True if conversion was successful. False, otherwise. */
bool toString(double input, utf8* output);

/*! \brief Convert double precision floating number to UTF-16 string.
	\param input Double to convert.
	\param output Pointer to output string.
	\return True if conversion was successful. False, otherwise. */
bool toString(double input, utf16* output);

/*! \brief Convert pointer to UTF-8 string.
	\param input Pointer to convert.
	\param output Pointer to output string.
	\return True if conversion was successful. False, otherwise. */
bool toString(void* input, utf8* output);

/*! \brief Convert pointer to UTF-16 string.
	\param input Pointer to convert.
	\param output Pointer to output string.
	\return True if conversion was successful. False, otherwise. */
bool toString(void* input, utf16* output);

/*! \brief Convert UTF-8 string to unsigned integer.
	\param input Pointer to input string.
	\param output Reference to converted float.
	\return True if conversion was successful. False, otherwise. */
bool toUnsignedInteger(utf8* input, unsigned int& output);

/*! \brief Convert UTF-16 string to unsigned integer.
	\param input Pointer to input string.
	\param output Reference to converted float.
	\return True if conversion was successful. False, otherwise. */
bool toUnsignedInteger(utf16* input, unsigned int& output);

}	// namespace Unicode

#endif